/**
 * 字符串操作封装类, 参考std::string, 主要考虑效率与短字符串的实现, 在字符少于15个时非常高效.
 * 非模板设计, 不提供字符类型,分配器等选项, 使用malloc序列分配内存, 提高编译进库, 加快第三方程序编译速度
 * 支持与std::string的操作, 添加,比较等.
 * 支持以NULL字符串构造或赋值, 等同于std::string的空串, 但data,c_str返回的是NULL而不是空串
 * 忽略一些std::string中不常用的接口, 如:迭代器相关
 * 已有接口命名与std::string相同
 * 
 * 开发者   : Marco
 * 创建时间 : 2017年5月19日, 下午5:45
 */

#ifndef __MARCOPP_STRING_HPP__
#define __MARCOPP_STRING_HPP__

#include "marcopp.h"
#include <iosfwd>

#define	MARCO_STRING_OUT_OF_RANGE   2	// 越界异常值
#define	MARCO_STRING_TOO_LONG	    1	// 超出范围异常值

MARCOPP_NAMESPACE_BEGIN

typedef unsigned long long  u64;

class string {
public:
    // 构造
    string(void) MARCOPP_NOEXCEPT;
    string(const char* str) MARCOPP_NOEXCEPT;
    string(const char* str, size_t len) MARCOPP_NOEXCEPT;
    string(const string& orig) MARCOPP_NOEXCEPT;
    string(const std::string& orig) MARCOPP_NOEXCEPT;
    string(size_t n, char ch) MARCOPP_NOEXCEPT;
#if (__cplusplus >= 201103L)
    string(string&& orig) MARCOPP_NOEXCEPT; // 移动构造
#endif
    
    // 赋值
    string& operator=(const string& orig) MARCOPP_NOEXCEPT;
    string& operator=(const std::string& orig) MARCOPP_NOEXCEPT;
    string& operator=(const char* str) MARCOPP_NOEXCEPT;
    string& operator=(const char ch) MARCOPP_NOEXCEPT;
#if (__cplusplus >= 201103L)
    inline string& operator=(string&& orig) MARCOPP_NOEXCEPT { swap(orig); return *this; }
#endif
    
    ~string(void); // 析构
    
    /**
     * 取当前长度
     */
    size_t size(void) const MARCOPP_NOEXCEPT;
    size_t length(void) const MARCOPP_NOEXCEPT;
    
    /**
     * 最大长度, 固定0x3fffffff
     */
    size_t max_size(void) const MARCOPP_NOEXCEPT;
//    void resize(int n, char c);
//    void resize(int n) { resize(n, 0); }
//    void shrink_to_fit();
    
    /**
     * 获取无需分配重新分配内存的大小
     * 与std::string不同的是: 当前是短串或空串时无需分配堆内存, 返回固定值(64位14, 32位10)
     */
    size_t capacity(void) const MARCOPP_NOEXCEPT; // 短串或空时返回短串最大字符数(64位14字符), 长串返回实际大小
    
    /**
     * 预留空间, 超过max_size时算max_size, 适用于频繁增加内容前预先分配足够大小, 防止不断申请内存并拷贝带来的性能损耗
     * 当前为短串或空串时, 预留大于短串最大大小(64位14, 32位10), 则提前转为长串模式
     * 预留大小小于等于当前长度时则移除预留大小, 使用刚好的内存, 适用于不再追加内容时减少占用资源
     * @param n 预留长度
     */
    void reserve(size_t n = 0);
    
    /**
     * 清空内容, 变为空串, 当是长串时则释放资源
     */
    void clear(void) MARCOPP_NOEXCEPT;
    
    /**
     * 是否为空串
     */
    bool empty(void) const MARCOPP_NOEXCEPT;
//    const_reference operator[] (size_type __pos) const  // 调试模式下assert越界检查
//    reference operator[](size_type __pos) // 调试模式下assert越界检查
//    const_reference at(size_type __n) const // 越界检查, 抛异常
//    reference at(size_type __n) // 越界检查, 抛异常
    
    /**
     * 获取指定下标的字符, 不检查越界, 与std::string不同, 并不返回迭代器
     * @param pos 下标, 如果越界其结果是未定义的
     * @return 指定下标的字符
     */
    char operator[] (size_t pos) const MARCOPP_NOEXCEPT { return data()[pos]; }
    
    /**
     * 获取指定下标的字符, 越界抛异常, 与std::string不同, 并不返回迭代器
     * @param pos 下标
     * @exception 越界时抛出int(MARCO_STRING_OUT_OF_RANGE)
     * @return 指定下标的字符
     */
    char at(size_t pos) const throw(int);
    
    /**
     * 追加内容
     * @param str 字符串
     * @exception 超过最大长度, throw(1)
     * @return 本对象引用
     */
    inline string& operator+= (const char* str) throw(int) { return append(str); };
    inline string& operator+= (const string& str) throw(int) { return append(str); }
    inline string& operator+= (const char ch) throw(int) { return append(&ch, 1); } // +上单个字符
    inline string& operator+= (const std::string& str) throw(int) { return append(str); }
    
    /**
     * 添加另一个string对象
     * @param str 待添加的string对象
     * @exception 超过最大长度, 抛出int(MARCO_STRING_TOO_LONG)
     * @return 本对象引用
     */
    inline string& append(const string& str) throw(int) { return append(str.data(), str.size()); }
    
    /**
     * 添加另一个string对象的部分内容
     * @param str 待添加的子串
     * @param pos 起始位置
     * @param n 添加字符个数, 超过实际剩余字符时按实际数处理
     * @exception 超过最大长度, 抛出int(MARCO_STRING_TOO_LONG), pos大于size(), 抛出int(MARCO_STRING_OUT_OF_RANGE)
     * @return 本对象引用
     */
    string& append(const string& str, size_t pos, size_t n) throw(int); // pos越界抛出int(MARCO_STRING_OUT_OF_RANGE)
    
    /**
     * 添加一个std::string对象
     * @param str 待添加的string对象
     * @exception 超过最大长度, 抛出int(MARCO_STRING_TOO_LONG)
     * @return 本对象引用
     */
    string& append(const std::string& str) throw(int);
    
    /**
     * 添加一个std::string对象的部分内容
     * @param str 待添加的子串
     * @param pos 起始位置
     * @param n 添加字符个数, 超过实际剩余字符时按实际数处理
     * @exception 超过最大长度, 抛出int(MARCO_STRING_TOO_LONG), pos大于size(), 抛出int(MARCO_STRING_OUT_OF_RANGE)
     * @return 本对象引用
     */
    string& append(const std::string& str, size_t pos, size_t n) throw(int);
    
    /**
     * 添加C字符串, 允许没有结束符
     * @param str C形式字符串, 与std::string不同的是, 空指针不会出现异常而是忽略
     * @param len 长度, 超出str范围, 结果是未定义的
     * @exception 超过最大长度, 抛出int(MARCO_STRING_TOO_LONG)
     * @return 本对象引用
     */
    string& append(const char* str, size_t len) throw(int);
    
    /**
     * 添加C字符串, 使用strlen取长度, 必须保证有结束符, 否则结果是未定义的
     * @param str C形式字符串, 与std::string不同的是, 空指针不会出现异常而是忽略
     * @exception 超过最大长度, 抛出int(MARCO_STRING_TOO_LONG)
     * @return 本对象引用
     */
    string& append(const char* str) throw(int);
    
    /**
     * 添加n个相同字符
     * @param n 个数
     * @param ch 字符
     * @exception 超过最大长度, 抛出int(MARCO_STRING_TOO_LONG)
     * @return 本对象引用
     */
    string& append(size_t n, char ch) throw(int); // 追加n个相当字符
    
    /**
     * 追加单个字符在最后
     * @param ch 字符
     * @exception 超过最大长度, 抛出int(MARCO_STRING_TOO_LONG)
     */
    inline void push_back(char ch) throw(int) { append(&ch, 1); } // 追加一个字符
    
    // 忽略c++11的initializer_list的重载
    // assign
    
    /**
     * 插入一个string对象部分内容到指定位置
     * @param pos 插入到本串的起始位置
     * @param ins_str 待插入的子串
     * @param ins_pos 子串的起始位置
     * @param ins_len 子串插入子符个数, 超过实际剩余字符数时, 按实际数处理
     * @exception 总长度大于max_size()抛出int(MARCO_STRING_TOO_LONG), pos大于size()或ins_pos大于ins_str.size()抛出int(MARCO_STRING_OUT_OF_RANGE)
     * @return 本对象引用
     */
    string& insert(size_t pos, const string& ins_str, size_t ins_pos, size_t ins_len) throw(int);
    
    /**
     * 插入一个std::string对象部分内容到指定位置
     * @param pos 插入到本串的起始位置
     * @param ins_str 待插入的子串
     * @param ins_pos 子串的起始位置
     * @param ins_len 子串插入子符个数, 超过实际剩余字符数时, 按实际数处理
     * @exception 总长度大于max_size()抛出int(MARCO_STRING_TOO_LONG), pos大于size()或ins_pos大于ins_str.size()抛出int(MARCO_STRING_OUT_OF_RANGE)
     * @return 本对象引用
     */
    string& insert(size_t pos, const std::string& ins_str, size_t ins_pos, size_t ins_len) throw(int);
    
    /**
     * 插入一个string对象所有内容到指定位置
     * @param pos 插入到本串的起始位置
     * @param ins_str 待插入的子串
     * @exception 总长度大于max_size()抛出int(MARCO_STRING_TOO_LONG), pos大于size()抛出int(MARCO_STRING_OUT_OF_RANGE)
     * @return 本对象引用
     */
    inline string& insert(size_t pos, const string& ins_str) throw(int) { return insert(pos, ins_str.data(), ins_str.size()); }
    
    /**
     * 插入一个std::string对象所有内容到指定位置
     * @param pos 插入到本串的起始位置
     * @param ins_str 待插入的子串
     * @exception 总长度大于max_size()抛出int(MARCO_STRING_TOO_LONG), pos大于size()抛出int(MARCO_STRING_OUT_OF_RANGE)
     * @return 本对象引用
     */
    string& insert(size_t pos, const std::string& ins_str) throw(int);
    
    /**
     * 插入一个C字符串部分内容到指定位置, 支持无结束符
     * @param pos 插入到本串的起始位置
     * @param ins_str 待插入的子串, 与std::string不同的是空指针不会引起崩溃, 而是忽略
     * @param ins_len 子串插入子符个数, 超出ins_str存储内容其结果是未定义的
     * @exception 总长度大于max_size()抛出int(MARCO_STRING_TOO_LONG)
     * @return 本对象引用
     */
    string& insert(size_t pos, const char* ins_str, size_t ins_len) throw(int);
    
    /**
     * 插入一个C字符串所有内容到指定位置, 使用strlen长度, 必须有结束符, 否则结果是未定义的
     * @param pos 插入到本串的起始位置
     * @param ins_str 待插入的子串, 与std::string不同的是空指针不会引起崩溃, 而是忽略
     * @exception 总长度大于max_size()抛出int(MARCO_STRING_TOO_LONG)
     * @return 本对象引用
     */
    string& insert(size_t pos, const char* ins_str) throw(int); // 同上, 空指针忽略, 使用strlen取长度
    
    // erase
    // replace
    
    /**
     * 拷贝字符到C样式的缓存
     * @param buf (out)存储区, 由调用处保证大小, 至少count+1长度(自动添加结束符0)
     * @param count 拷贝的字符个数
     * @param pos 起始位置, 从0开始, 当起始位置越界与std::string不同的是,不抛出异常而返回0
     * @return 实际拷贝的字符个数
     */
    size_t copy(char* buf, size_t count, size_t pos = 0) const MARCOPP_NOEXCEPT;
    
    /**
     * 交换两个对象
     * @param str 要交换的对象
     */
    void swap(string& str) MARCOPP_NOEXCEPT;
    
    /**
     * 返回C形式的原始字符指针
     * @return 指针地址或NULL
     */
    const char* data(void) const MARCOPP_NOEXCEPT;
    const char* c_str(void) const MARCOPP_NOEXCEPT;
    
    // find
    // rfind
    // find_first_of
    // find_last_of
    // find_first_not_of
    // find_last_not_of
    // substr
    
    /**
     * 比较两个对象是否大小
     * @param str 要比较的串
     * @return 0相等, 大于0本对象大, 小于0本对象小
     */
    int compare(const string& str) const MARCOPP_NOEXCEPT;
    int compare(const std::string& str) const MARCOPP_NOEXCEPT;
    int compare(const char* str) const MARCOPP_NOEXCEPT;
    
private:
    void set(const char* str, size_t len);
    string& assign(const char* str, size_t len);
    
    char* ptr_;
    union {
	struct {
	    u64 capacity_ : 30;
	    u64 len_ : 30;
	    u64 flg_ : 4;
	};
	u64 fill_;
    };
};

//string to_string(int __val);

// operator+ 
inline string operator+(const string& left, const string& right) { string str(left); str.append(right); return str; } // string

inline string operator+(const string& left, const std::string& right) { string str(left); str.append(right); return str; } // std::string
inline string operator+(const std::string& left, const string& right) { string str(left); str.append(right); return str; }

inline string operator+(const string& left, const char* right) { string str(left); str.append(right); return str; } // const char*
inline string operator+(const char* left, const string& right) { string str(left); str.append(right); return str; }

inline string operator+(const string& left, char right) { string str(left); str.push_back(right); return str; } // char
inline string operator+(char left, const string& right) { string str(1, left); str.append(right); return str; }

#if __cplusplus >= 201103L
string operator+(string&& left, const string& right); // string
string operator+(const string& left, string&& right);
string operator+(string&& left, string&& right);

string operator+(const std::string& left, string&& right); // std::string
string operator+(string&& left, std::string right);

string operator+(string&& left, const char* right); // const char*
string operator+(const char* left, string&& right);

string operator+(string&& left, char right); // char
string operator+(char left, string&& right);
#endif


/** 是否相等, 与std::string不同的是, 空指针(NULL)当作空串处理, 不会崩溃 */
inline bool operator==(const string& left, const string& right) { return left.compare(right) == 0; }
inline bool operator==(const string& left, const std::string& right) { return left.compare(right) == 0; }
inline bool operator==(const std::string& left, const string& right) { return right.compare(left) == 0; }
inline bool operator==(const string& left, const char* str) { return left.compare(str) == 0; }
inline bool operator==(const char* str, const string& right) { return right.compare(str) == 0; }

inline bool operator!=(const string& left, const string& right) { return !(left == right); }
inline bool operator!=(const string& left, const std::string& right) { return !(left == right); }
inline bool operator!=(const std::string& left, const string& right) { return !(left == right); }
inline bool operator!=(const string& left, const char* str) { return !(left == str); }
inline bool operator!=(const char* str, const string& right) { return !(str == right); }

inline bool operator<(const string& left, const string& right) { return left.compare(right) < 0; }
inline bool operator<(const string& left, const std::string& right) { return left.compare(right) < 0; }
inline bool operator<(const std::string& left, const string& right) { return right.compare(left) > 0; }
inline bool operator<(const string& left, const char* str) { return left.compare(str) < 0; }
inline bool operator<(const char* str, const string& right) { return right.compare(str) > 0; }

inline bool operator>(const string& left, const string& right) { return left.compare(right) > 0; }
inline bool operator>(const string& left, const std::string& right) { return left.compare(right) > 0; }
inline bool operator>(const std::string& left, const string& right) { return right.compare(left) <= 0; }
inline bool operator>(const string& left, const char* str) { return left.compare(str) > 0; }
inline bool operator>(const char* str, const string& right) { return right.compare(str) <= 0; }

inline bool operator<=(const string& left, const string& right) { return left.compare(right) <= 0; }
inline bool operator<=(const string& left, const std::string& right) { return left.compare(right) <= 0; }
inline bool operator<=(const std::string& left, const string& right) { return right.compare(left) >= 0; }
inline bool operator<=(const string& left, const char* str) { return left.compare(str) <= 0; }
inline bool operator<=(const char* str, const string& right) { return right.compare(str) >= 0; }

inline bool operator>=(const string& left, const string& right) { return left.compare(right) >= 0; }
inline bool operator>=(const string& left, const std::string& right) { return left.compare(right) >= 0; }
inline bool operator>=(const std::string& left, const string& right) { return right.compare(left) <= 0; }
inline bool operator>=(const string& left, const char* str) { return left.compare(str) >= 0; }
inline bool operator>=(const char* str, const string& right) { return right.compare(str) <= 0; }

std::ostream& operator<<(std::ostream& output, const string& str);
inline void swap(string& left, string& right) { left.swap(right); }

MARCOPP_NAMESPACE_END
#endif /* __MARCOPP_STRING_HPP__ */

